import os.path
import xml.dom.minidom as xml
import tempfile
from Cheetah.Template import Template
import Lise
import Error
import MacFinderColourFile



class LiseXML(Lise.Lise):
    """
    Implements the read/write operations between a LiSe definition in memory (Lise instance) 
    and a XML file

    """

    def __init__(self, lisePath):
        """Arguments:
        lisePath(string) -- LiSe XML file path

        """
        Lise.Lise.__init__(self)
        self.lisePath = lisePath

    def GetLisePath(self):
        return self.lisePath



    def _getTextByNode(self, node, defaultReturnValue=''):
        """ Returns all the plain text contained into the specified XML node

        Arguments:
        node -- A node instance of the xml.dom.minidom type
        defaultReturnValue(string) -- To be returned if no text is found

        """
        text = ''
        for child in node.childNodes:
            if child.nodeType == xml.Node.TEXT_NODE or \
                child.nodeType == xml.Node.CDATA_SECTION_NODE:
                text += child.data
        if len(text) > 0:
            return text
        else:
            return defaultReturnValue

    def _getTextByTagName(self, node, tagName, defaultReturnValue=''):
        """ Searches the first XML child node with the specified tangame and returns all the 
        plain text contained

        Arguments:
        node -- A node instance of the xml.dom.minidom type
        tagName(string) -- The tag name of the node to find
        defaultReturnValue(string) -- To be returned if no text is found

        """
        tagList = node.getElementsByTagName(tagName)
        if len(tagList) > 0:
            return self._getTextByNode(tagList[0], defaultReturnValue)
        else:
            return defaultReturnValue

    def _GetTextByChildNode(self, node, tagName):
        text = '' 
        for tag in [i for i in node.childNodes
                    if i.nodeType == xml.Node.ELEMENT_NODE and i.nodeName == tagName]:
           text += self._getTextByNode(tag)
        return text

    def _ReadIndexFromXML(self, node, chapterTitle=None):
        """Returns a list of LisePage|LiseInterval|LiseChapter instances related to the list of 
        pages found in the specified node of the XML LiSe file. That node must be the root one of 
        the index, or the root of a chapter.

        Arguments:
        node -- A node instance of the xml.dom.minidom type
        chapterTitle(string) -- The title of the parent chapter of the list of pages that will be 
                                returned.  None if the call of this method is done for the root 
                                node of the index

        """
        pageList = []
        for tag in node.childNodes:
            if tag.nodeType == xml.Node.ELEMENT_NODE:
                if tag.nodeName == 'page':
                    pageTitle = self._getTextByTagName(tag, 'pagetitle')
                    if tag.getAttribute('picturesperpage') != '':
                        picturesPerPage = int(tag.getAttribute('picturesperpage'))
                    else:
                        picturesPerPage = 1
                    tagsNotes = tag.getElementsByTagName('notes')
                    if len(tagsNotes) > 0:
                        tagNotes = tagsNotes[0]
                        notes = self._getTextByTagName(tag, 'notes')
                        if tagNotes.getAttribute('notesstyle') != '':
                            notesStyle = int(tagNotes.getAttribute('notesstyle'))
                        else:
                            notesStyle = None
                    else:
                        notes = ''
                        notesStyle = None
                    pageList.append(Lise.LisePage(pageTitle, picturesPerPage, notes, notesStyle))
                elif tag.nodeName == 'interval':
                    from_ = int(tag.getAttribute('from'))
                    to_ = int(tag.getAttribute('to'))
                    prefix = tag.getAttribute('prefix')
                    suffix = tag.getAttribute('suffix')
                    pageList.append(Lise.LiseInterval(from_, to_, prefix, suffix))
                elif tag.nodeName == 'chapter':
                    # Recursive call of the method when parsing a chapter
                    subChapterTitle = self._getTextByTagName(tag, 'chaptertitle')
                    pageList.append(self._ReadIndexFromXML(tag, subChapterTitle))

        if chapterTitle is None:
            # If this iteration was called by the root node of the index
            return pageList
        else:
            # If this iteration was called by a chapter of the index
            return Lise.LiseChapter(chapterTitle, pageList)

    def _ReadWorkflowFromXML(self, node):
        tasks = []
        for tag in node.childNodes:
            if tag.nodeType == xml.Node.ELEMENT_NODE:
                if tag.nodeName == 'task':
                    name = self._GetTextByChildNode(tag, 'name')
                    notes = self._GetTextByChildNode(tag, 'notes')
                    checked = tag.getAttribute('checked') != ''
                    subtasks = self._ReadWorkflowFromXML(tag)
                    tasks.append(Lise.LiseWorkflow(name, checked, subtasks, notes))
        return tasks

    def ReadFromXML(self):
        """
        Parses a LiSe XML file v2 and stores all the metadata into a Lise instance in memory

        """
        # Parses the XML LiSe file
        try:
            dom = xml.parse(self.lisePath)
            tagLise = dom.documentElement
        except IOError:
            raise Error.Error(101, 'Error reading the LiSe XML file: "' + self.lisePath + '"')
        except:
            raise Error.Error(102, 'Error parsing the LiSe XML file: "' + self.lisePath + '"')
        # Retrieves the "digiSubdir" and "templateId" LiSe attributes
        digiSubdir = self._getTextByTagName(tagLise, 'digisubdir')
        templateId = self._getTextByTagName(tagLise, 'templateid')

        # Retrieves the workflow tasks
        tagsWorkflow = tagLise.getElementsByTagName('workflow')
        workflow = self._ReadWorkflowFromXML(tagsWorkflow[0]) if len(tagsWorkflow) > 0 else []

        # Retrieves the rest of the metadata (to a dict of LiseMetadata instances)
        metadata = {}
        for tagMetadata in tagLise.getElementsByTagName('metadata'):
            lang = tagMetadata.getAttribute('lang')
            author = self._getTextByTagName(tagMetadata, 'author')
            title = self._getTextByTagName(tagMetadata, 'title')
            year = self._getTextByTagName(tagMetadata, 'year')
            owner = self._getTextByTagName(tagMetadata, 'owner')

            # Retrieves the index of the document
            tagsIndex = tagMetadata.getElementsByTagName('index')
            index = self._ReadIndexFromXML(tagsIndex[0]) if len(tagsIndex) > 0 else []

            metadata[lang] = Lise.LiseMetadata(author, title, year, owner, index)

        Lise.Lise.__init__(self, digiSubdir, templateId, metadata, workflow)
        self.digiDirPath = os.path.join(os.path.dirname(self.lisePath), self.digiSubdir)


    def _getPageListByNodeLise1(self, node, chapterTitle=None):
        """Read the getPageListByNode method comments"""
        pageList = []
        for tag in node.childNodes:
            if tag.nodeType == xml.Node.ELEMENT_NODE:
                if tag.nodeName == 'page':
                    pageTitle = self._getTextByTagName(tag, 'pagetitle')
                    notes = self._getTextByTagName(tag, 'text')
                    notes = notes.replace('|BR|', "\n")
                    pageList.append(Lise.LisePage(pageTitle, 1, notes))
                elif tag.nodeName == 'interval':
                    from_ = int(tag.getAttribute('from'))
                    to_ = int(tag.getAttribute('to'))
                    prefix = tag.getAttribute('prefix')
                    suffix = tag.getAttribute('suffix')
                    pageList.append(Lise.LiseInterval(from_, to_, prefix, suffix))
                elif tag.nodeName == 'chapter':
                    # Recursive call of the method when parsing a chapter
                    subChapterTitle = self._getTextByTagName(tag, 'chaptertitle')
                    pageList.append(self._getPageListByNodeLise1(tag, subChapterTitle))

        if chapterTitle is None:
            # If this iteration was called by the root node of the index
            return pageList
        else:
            # If this iteration was called by a chapter of the index
            return Lise.LiseChapter(chapterTitle, pageList)

    def readFromXMLLise1(self):
        """
        Parses a LiSe XML file v1 and stores all the metadata into a Lise instance in memory

        """
        notePageTitle = {'es':'Nota', 'en':'Note'}

        # Parses the XML LiSe file
        dom = xml.parse(self.lisePath)
        tagLise = dom.documentElement

        # Retrieves the "id" and "templateId" LiSe attributes
        id = self._getTextByTagName(tagLise, 'picturedir')
        digiSubdir = id
        templateId = self._getTextByTagName(tagLise, 'template')

        pictures = []

        # Retrieves the rest of the metadata (to a dict of LiseMetadata instances)
        metadata = {}
        for tagMetadata in tagLise.getElementsByTagName('language'):
            langId = tagMetadata.getAttribute('id')
            author = self._getTextByTagName(tagMetadata, 'author')
            title = self._getTextByTagName(tagMetadata, 'title')
            title = title.replace('|BR|', "\n")
            year = self._getTextByTagName(tagMetadata, 'year')
            owner = self._getTextByTagName(tagMetadata, 'owner')
            description = self._getTextByTagName(tagMetadata, 'note')
            tagsDescription = tagMetadata.getElementsByTagName('note')
            if len(tagsDescription) > 0 and tagsDescription[0].getAttribute('blanklines') != '':
                notesStyle = int(tagsDescription[0].getAttribute('blanklines'))
            else:
                notesStyle = None

            # Retrieves the index of the document
            tagsIndex = tagMetadata.getElementsByTagName('index')
            if len(tagsIndex) > 0:
                index = self._getPageListByNodeLise1(tagsIndex[0])
            else:
                index = []

            # Adds the note to the index
            if len(description) > 0:
                index.insert(0, Lise.LisePage(notePageTitle[langId], 0, description, notesStyle*25))

            metadata[langId] = Lise.LiseMetadata(author, title, year, owner, index)

        Lise.Lise.__init__(self, id, digiSubdir, templateId, pictures, metadata)
        self.digiDirPath = os.path.join(os.path.dirname(self.lisePath), self.digiSubdir)



    def WriteToXML(self, outputPath=None):
        """
        Writes/creates a LiSe XML file from all the metadata stored in a Lise instance in memory

        """
        if outputPath is None:
            outputPath = self.lisePath
        # Retrieves all the metadata in an apropiate format for the Cheetah template
        nameSpace = self.toNameSpace(False, False)
        nameSpace['metadata'] = {}
        for key, value in self.metadata.items():
            nameSpace['metadata'][key] = value.toNameSpace(False, False)
            nameSpace['metadata'][key]['index'] = value.getIndexPlainList()
        nameSpace['workflow'] = self.GetWorkflowPlainList()
        # Fills the metadata in the template and generates the lise XML file
        try:
            t = Template(file=os.path.join(self._determine_path(), 'templates','lise.tmpl'), 
                         searchList=[nameSpace])
        except:
            raise Error.Error(150, 'Error filling in the XML LiSe template')
        #try:
        (handle, tempfilePath) = tempfile.mkstemp(suffix=os.path.basename(outputPath)+'_', 
                                                      prefix='tmp_', 
                                                      dir=os.path.dirname(outputPath))
        os.write(handle, str(t))
        os.close(handle)
        #except:
        #    raise Error.Error(151, 'Error generating the XML LiSe file')
        try:
            os.rename(tempfilePath, outputPath) 
        except:
            raise Error.Error(152, "Error writing the XML LiSe file '" + outputPath + "'")
        MacFinderColourFile.MacFinderColourFile([outputPath], MacFinderColourFile.LABEL_ORANGE)



    def _determine_path(self):
        """Borrowed from wxglade.py"""
        try:
            root = __file__
            if os.path.islink(root):
                root = os.path.realpath(root)
            return os.path.dirname(os.path.abspath(root))
        except:
            print "I'm sorry, but something is wrong."
            print "There is no __file__ variable. Please contact the author."
            sys.exit()



